<?php

namespace app\common\service;

use app\common\exception\BackErrorException;
use app\common\model\Recommend;
use app\common\model\Topic;
use app\common\model\UserFavorVideo as UserFavorVideoModel;
use app\common\model\UserStudy;
use app\common\model\VideoList;
use app\common\model\VideoList as VideoListModel;
use app\common\model\Category as CategoryModel;
use app\common\model\VideoWord;
use app\common\model\WordDict;
use EasyWeChat\Factory;
use think\Collection;
use think\Exception;
use think\facade\Db;


/**
 * 本地视频的管理 不是阿里云视频的管理
 */
class VideoService extends BaseServices
{
    /**
     * 管理员
     * @var int
     */
    protected $isAdminId = 1;

    public function getOne($id)
    {
        return VideoListModel::where(['id' => $id])->find();
    }

    /**
     * 分页获取全部单词
     * @param $page
     * @param $pageSize
     * @return array
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function getWordList($page, $pageSize)
    {
        $wordResult = [];
        $model = WordDict::where(['is_delete' => $this->noDelete]);
        $this->formatPage($model, $page, $pageSize);
        $wordInfo = $model->column('id,word,cn,is_delete,create_time');
        if ($wordInfo) {
            $wordResult = Collection::make($wordInfo)->toArray();
            foreach ($wordResult as &$item) {
                $item['create_time'] = date('Y-m-d H:i:s', $item['create_time']);
            }
        }
        return ['list' => $wordResult];
    }

    /**
     * 获取视频单词
     * @param $page
     * @param $pageSize
     * @param $videoId
     * @return array[]
     * @throws BackErrorException
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function getVideoWordList($page, $pageSize, $videoId)
    {
        if (empty($videoId)) {
            throw new BackErrorException("视频id不能未空");
        }
        if (!$this->getOne($videoId)) {
            throw new BackErrorException("该视频信息有误，请检查");
        }
        $wordResult = VideoWord::where(['video_id' => $videoId, 'is_delete' => $this->noDelete])->select();
        $wordResult = Collection::make($wordResult)->toArray();
        $wordIds = array_column($wordResult, 'word_id');
        $wordInfo = [];
        if (!empty($wordIds)) {
            $model = WordDict::whereIn('id', $wordIds)->where(['is_delete' => $this->noDelete]);
            $this->formatPage($model, $page, $pageSize);
            $wordInfo = $model->select();
            $wordInfo = $wordInfo->toArray();
        }
        return ['list' => $wordInfo];
    }

    /**
     * 给视频或添加单词
     * @param $params
     * @return bool
     * @throws BackErrorException
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function addVideoWord($params)
    {
        if (!$this->checkWordExits($params['word'], $params['cn'])) {
            throw new BackErrorException("已存在该单词，请检查");
        }
        $videoFlag = false;
        if (isset($params['video_id']) && !empty($params['video_id'])) {
            $videoFlag = true;
        }
        if ($videoFlag && !$this->getOne($params['video_id'])) {
            throw new BackErrorException("该视频信息有误，请检查");
        }
        Db::startTrans();
        try {
            $wordData =  ['word' => $params['word'], 'cn' => $params['cn']];
            $this->formatData($wordData);
            $id = (new WordDict())->insertGetId($wordData);
            if (!$id) {
                Db::rollback();
            }
            if ($videoFlag) {
                $videoData = ['video_id' => $params['video_id'], 'word_id' => $id];
                $this->formatData($videoData);
                if (!(new VideoWord())->save($videoData)) {
                    Db::rollback();
                }
            }
            Db::commit();
        } catch (\Exception $e) {
            Db::rollback();
            throw new BackErrorException($e->getMessage() ?? '删除认领失败');
        }
        return true;
    }

    /**
     * 检查单词是否存在
     * @param $word
     * @param $cn
     * @return bool
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function checkWordExits($word, $cn)
    {
        $where = [
            'word' => $word,
            'cn' => $cn,
            'is_delete' => $this->noDelete
        ];
        $res = WordDict::where($where)->column('id');
        if ($res) {
            return false;
        }
        return true;
    }

    /**
     * 设置专栏视频排序
     * @param $id
     * @param $sort
     * @throws BackErrorException
     */
    public function setSort($id, $sort)
    {
        if ((int)$sort < 1 || (int)$sort > 9999) {
            throw new BackErrorException("请设置合理排序值");
        }
        if (!$this->getOne($id)) {
            throw new BackErrorException("该视频信息有误，请检查");
        }
        if (!(new VideoList())->update(['sort' => $sort], ['id' => $id])) {
            throw new BackErrorException("设置该视频排序失败");
        }
        return true;
    }

    /**
     * 根据topicId获取视频信息
     * @param $topicId
     * @return \think\Collection
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function getVideoByTopicId($topicId)
    {
        return VideoListModel::where(['topic_id' => $topicId, 'delete_time' => $this->noDelete])->select();
    }

    /**
     * 绑定关联视频到topic
     * @param $video
     * @return VideoListModel|false
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function updateFeeAndTopic($video)
    {
        $checkResult = VideoListModel::find($video['video_id']);
        if (!$checkResult) {
            return false;
        }
        $videoIds = explode(',', $video['video_id']);
        foreach ($videoIds as $id) {
            VideoListModel::update(['fee' => $video['fee'], 'topic_id' => $video['topic_id']], ['id' => $id]);
        }
        return true;
    }

    /**
     * 删除关联视频
     * @param $params
     * @return VideoListModel|false
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function updateTopic($params, $update)
    {
        $where = [
            'topic_id' => $params['topic_id'],
            'id' => $params['video_id']
        ];
        $checkResult = VideoListModel::where($where)->find();
        if (!$checkResult) {
            return false;
        }
        return VideoListModel::update($update, ['id' => $params['video_id']]);
    }

    /**
     * 收藏和取消 一个方法
     * @param $videoId
     * @param $uid
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function updateFavor($videoId, $uid)
    {
        $favor = UserFavorVideoModel::where(['video_id' => $videoId, 'uid' => $uid])->find();
        if (empty($favor)) {
            UserFavorVideoModel::create([
                'video_id' => $videoId,
                'uid' => $uid
            ]);
        } else {
            $favor->delete();
            $result = VideoListModel::where('id', $videoId)->find()->toArray();
            //修复收藏人数为负数
            if ($result['favor'] > 0) {
                VideoListModel::where('id', $videoId)->dec('favor')->update();
            }
        }
    }


    public function favorStatus($videoId, $uid)
    {
        $res = VideoListModel::where(['id' => $videoId])->column("favor");
        $isFavor = UserFavorVideoModel::where(['video_id' => $videoId, 'uid' => $uid])->count();
        return ['favorNum' => $res[0], 'isFavor' => $isFavor];
    }

    /**
     * 获取未关联列表
     * @param $page
     * @param $pageSize
     * @param $user
     * @return array
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function getNoClaimVideo($page, $pageSize, $user)
    {
        app(VideoClaimService::class)->deleteVideoByTime($user['id']);
        //1、先获取所有已关联视频id
        //2、在获取所有视频列表
        $list = [];
        $videoIds =  $this->getExistVidelId();
        $videoIds = array_keys($videoIds);
        $where['delete_time'] = 0;
        $count = VideoListModel::where($where);
        if (!empty($videoIds)) {
            $count = $count->whereNotIn('id', $videoIds);
        }
        $count = $count->count();
        if ($count) {
            $start = ($page - 1) * $pageSize;
            $list = VideoListModel::where($where);
            if (!empty($videoIds)) {
                $list = $list->whereNotIn('id',  $videoIds);
            }
            $list = $list->order('id', 'desc')->limit($start, $pageSize)->select()->toArray();
            $this->dealWithCateTopic($list);
        }
        return ['total' => $count, 'list' => $list];
    }


    /**
     * 是否为admin
     * @param $user
     * @return bool
     */
    public function isAdmin($user)
    {
        return in_array("admin", $user['roles']);
    }

    /**
     * 获取已关联视频id
     * @param $uid
     * @return array
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function getExistVidelId($uid = 0)
    {
        $vlaimRes = app(VideoClaimService::class)->getClaimList($uid);
        if (!$vlaimRes) {
            $vlaimId = [];
        } else {
            foreach ($vlaimRes as $item) {
                $vlaimId[$item['video_id']] = $item['create_time'];
            }
        }
        return $vlaimId;
    }

    /**
     * 获取不同角色的视频列表
     * @param $page
     * @param $pageSize
     * @param $user
     * @return array
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function getListByRole($page, $pageSize, $user, $searchField, $searchValue, $status)
    {
        app(VideoClaimService::class)->deleteVideoByTime($user['id']);
        $where['delete_time'] = $status;
        //非管理员只能获取已认领视频id
        if (!$this->isAdmin($user)) {
            $where['id'] = $this->getExistVidelId($user['id']);
        }
        return $this->getVideoClaimList($page, $pageSize, $where, $searchField, $searchValue);
    }

    /**
     * 获取认领视频列表
     * @param $page
     * @param $pageSize
     * @param $where
     * @return array
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function getVideoClaimList($page, $pageSize, $where, $searchField, $searchValue)
    {
        $searchDefault = [
            'title',
            'desc'
        ];
        if (isset($where['id']) && empty($where['id'])) {
            //非管理员，且未关联视频
            $count = 0;
            $list = [];
        } else {
            $model = VideoListModel::where(['delete_time' => $where['delete_time']]);
            $this->formatLikeSearch($model, $searchField, $searchValue, $searchDefault);
            if (!empty($where['id'])) {
                $model = $model->whereIn('id', array_keys($where['id']));
            }
            $count = $model->count();
            if (!$count || $count == 0) {
                $list = [];
            } else {
                $list = $model->order('update_time', 'desc')->page($page, $pageSize)->select()->toArray();
                $this->dealWithCateTopic($list, $where['id'] ?? []);
            }
        }
        return ['total' => $count, 'list' => $list];
    }

    /**
     * 处理分类和topic信息
     * @param $list
     * @param array $claimInfo
     */
    public function dealWithCateTopic(&$list, $claimInfo = [])
    {
        $categoryInfo = $this->getCategoriesName(array_unique(array_column($list, 'category_id')));
        $topicInfo = $this->getTopicInfo(array_unique(array_column($list, 'topic_id')));
        foreach ($list as $key => $val) {
            $list[$key]['categoryInfo'] = $categoryInfo[$val['category_id']] ?? [];
            $list[$key]['topicInfo'] = $topicInfo[$val['topic_id']] ?? [];
            if (isset($claimInfo[$val['id']])) {
                $list[$key]['last_time'] = $this->getLastDay($claimInfo[$val['id']]);
            }
        }
    }

    /**
     * 获取剩余天数
     * @param $times
     * @return string
     */
    public function getLastDay($times)
    {
        if (is_string($times)) {
            $times = strtotime($times);
        }
        $secs = time() - $times;
        $diffDays = 7 - floor($secs / 86400);
        return $diffDays > 0 ? $diffDays : 0;
    }

    /**
     * 获取非关联视频id
     * @param $ids
     * @param $page
     * @param $pageSize
     * @return array
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function getSomeVideoLists($ids, $page, $pageSize)
    {
        $where['delete_time'] = 0;
        $start = ($page - 1) * $pageSize;
        $list = [];
        $count = VideoListModel::where($where)->whereNotIn('id', $ids)->count();
        if ($count) {
            $list = VideoListModel::where($where)
                ->order('id', 'desc')
                ->limit($start, $pageSize)->select()->toArray();
            $this->dealWithCateTopic($list);
        }
        return ['total' => $count, 'list' => $list];
    }

    /**
     * 获取分类信息
     * @param $cateIds
     * @return array
     */
    public function getCategoriesName($cateIds)
    {
        return Db::table('category')->whereIn("id", $cateIds)->column("id, name", "id");
    }

    /**
     * 获取主题信息
     * @param $topicIds
     * @return array
     */
    public function getTopicInfo($topicIds)
    {
        return Db::table("topic")->whereIn("id", $topicIds)->column("id, title", "id");
    }

    public function getList($page, $pageSize, $where, $order = 'id')
    {
        $start = ($page - 1) * $pageSize;
        $count = VideoListModel::where($where)->count();
        $list = VideoListModel::where($where)->order($order, 'desc')->limit($start, $pageSize)->select();
        $categoryIds = [];
        $topicIds = [];
        foreach ($list as $key => $val) {
            array_push($categoryIds, $val['category_id']);
            array_push($topicIds, $val['topic_id']);
        }
        $categories = Db::table('category')->whereIn("id", $categoryIds)->column("id,name", "id");
        $topics = Db::table("topic")->whereIn("id", $topicIds)->column("id,title", "id");

        foreach ($list as $key => $val) {
            $list[$key]['categoryInfo'] = empty($categories[$val['category_id']]) ? [] : $categories[$val['category_id']];
            $list[$key]['topicInfo'] = empty($topics[$val['topic_id']]) ? [] : $topics[$val['topic_id']];
        }

        return ['total' => $count, 'list' => $list];
    }

    public function create($data)
    {
        $category = CategoryModel::where(['id' => $data['category_id']])->find();
        $data['parent_category_id'] = $category['parent_id'];
        if (!isset($data['status'])) {
            $data['status'] = 0;
        }
        return VideoListModel::create($data);
    }

    public function update($data, $id)
    {
        $video = VideoListModel::find($id);
        $originTopicId = $video->topic_id;
        if ($video) {
            // 改变专栏时，为新专栏的关注用户发送上新提醒
            if ($originTopicId != $data['topic_id']) {
                // 配置接口
                $config = [
                    'app_id' => env('WXMP.APPID'),
                    'secret' => env('WXMP.SECRET'),
                    'token' => env('WXMP.TOKEN'),
                    'response_type' => 'array',
                ];
                $service = Factory::officialAccount($config);
                // 获取数据
                $category = CategoryModel::where('id', $data['category_id'])->value('name');
                $topic = Topic::find($data['topic_id']);
                $topicURL = 'http://' . env('APP_HOST') . '/zhuantimulu.html?id=' . $topic->id;
                $users = Db::table('study_plan')
                    ->alias('sp')
                    ->join('wechat_user u', 'sp.uid = u.id')
                    ->where(['u.remind_study' => 1, 'sp.src_id' => $data['topic_id'], 'sp.type' => 2])
                    ->field('u.nick_name,u.openid')
                    ->select();
                if (count($users)) {
                    foreach ($users as $user) {
                        $service->template_message->send([
                            'touser' => $user['openid'],
                            'template_id' => config('mp.template.newClass'),
                            'url' => $topicURL,
                            'data' => [
                                'first' => '您关注的课程更新啦！',
                                'keyword1' => $topic->title,
                                'keyword2' => $category,
                                'keyword3' => '医课',
                                'keyword4' => date('Y-m-d H:i:s'),
                                'remark' => ''
                            ],
                        ]);
                    }
                }
            }
            return VideoListModel::update($data, ['id' => $id]);
        } else {
            return false;
        }
    }

    public function addHot($id)
    {
        $model = VideoListModel::where(['id' => $id])->find()->toArray();
        $model['hot'] = $model['hot'] + 1;
        $this->update($model, $id);
    }

    /**
     * 软删---下架视频
     * 视频删除会影响 收藏  专栏播放数量 视频的推荐
     * 物理删除， 用户在收藏中查看的时候 如果发现某视频没有 就当时删除掉该视频的收藏 因为后台管不了用户的收藏
     * 专栏的播放量是累积的，不管
     * @param $id
     * @throws BackErrorException
     */
    public function remove($id)
    {
        //如果有推荐则不能删除 要先删除推荐
        $exists = Recommend::where(['src_id' => $id, 'type' => 1])->find();
        if (!empty($exists)) {
            throw new BackErrorException("该视频在推荐视频中，请先删除该视频推荐");
        }
        VideoListModel::update(['delete_time' => $this->isDelete], ['id' => $id]);
    }

    /**
     * 上架视频
     * @param $id
     * @return mixed
     * @throws BackErrorException
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function shelvesVideo($id)
    {
        $exists = VideoListModel::where(['id' => $id])->find();
        if (empty($exists)) {
            throw new BackErrorException("该视频不存在，请检查~");
        }
        if (!VideoListModel::update(['delete_time' => $this->noDelete], ['id' => $id])) {
            throw new BackErrorException("上架失败");
        }
        return true;
    }

    public function words($id)
    {
        $words = VideoWord::where(['video_id' => $id])->column("word_id");
        $words = Db::table("word_dict")->whereIn('id', $words)->select();
        return $words;
    }

    public function clearWordScreen($videoId, $adminId)
    {
        //权限判断
        $video = Db::table("video_list")->where(['id' => $videoId])->find();
        if (empty($video)) {
            throw new BackErrorException("视频不存在");
        }

        if ($video['wordscreen_editor'] != 0 && $video['wordscreen_editor'] != $adminId) {
            throw new BackErrorException("没有操作权限");
        }

        Db::table("video_wordscreen")->where(['video_id' => $videoId])->delete();

    }

    public function getWordScreen($videoId, $page = 1, $pageSize = 10)
    {
        $start = ($page - 1) * $pageSize;
        $list = Db::table('video_wordscreen')->where(['video_id' => $videoId])->order('start', 'asc')->limit($start, $pageSize)->select();
        $count = Db::table('video_wordscreen')->where(['video_id' => $videoId])->count();
        return ['total' => $count, 'list' => $list];
    }

    public function getWordScreenNoPage($videoId)
    {
        return Db::table("video_wordscreen")->where(['video_id' => $videoId])->order('start', 'asc')->column('id,en,cn,start_second,end_second,start_millisecond,end_millisecond', "start_second");
    }

    public function getWordScreenItem($id)
    {
        return Db::table("video_wordscreen")->where(['id' => $id])->find();
    }

    public function saveWordScreenItem($data, $adminId)
    {
        //权限判断
        $video = Db::table("video_list")->where(['id' => $data['video_id']])->find();
        if (empty($video)) {
            throw new BackErrorException("视频不存在");
        }

        if ($video['wordscreen_editor'] != 0 && $video['wordscreen_editor'] != $adminId) {
            throw new BackErrorException("没有编辑权限");
        }

        $regex = '/(\d{2}):(\d{2}):(\d{2}),(\d{3})/';
        //时间的处理

        $result = preg_match($regex, $data['start'], $match);
        if (!$result) {
            throw new BackErrorException("开始时间格式不对");
        }
        $data['start_second'] = intval($match[1]) * 3600 + intval($match[2]) * 60 + intval($match[3]);
        $data['start_millisecond'] = intval($match[4]) * 0.001;

        $result = preg_match($regex, $data['end'], $match);
        if (!$result) {
            throw new BackErrorException("结束时间格式不对");
        }
        $data['end_second'] = intval($match[1]) * 3600 + intval($match[2]) * 60 + intval($match[3]);
        $data['end_millisecond'] = intval($match[4]) * 0.001;
        Db::table("video_wordscreen_log")->insert([
            'video_id' => $data['video_id'],
            'wordscreen_id' => $data['id'],
            'content' => serialize($data),
            'op_id' => $adminId,
            'create_time' => time()
        ]);

        Db::table('video_list')->where(['id' => $data['video_id']])->update([
            'status' => 1,
            'wordscreen_editor' => $adminId
        ]);
        return empty($data['id']) ? Db::table("video_wordscreen")->insert($data) : Db::table("video_wordscreen")->where(['id' => $data['id']])->update($data);
    }

    public function outputWordScreen($id)
    {
        $video = Db::table('video_list')->where(['id' => $id])->find();
        if (empty($video) || is_null($video)) {
            throw new BackErrorException('视频信息有误，请检查~');
        }
        $list = Db::table('video_wordscreen')->where(['video_id' => $id])->select();
        if (empty($list) || is_null($list)) {
            throw new BackErrorException('此视频暂无字幕信息，请检查~');
        }
        $list = Collection::make($list)->toArray();
        $data = [];
        foreach ($list as $k => $item) {
            $data[] = $k + 1 . "\r\n{$item['start']} --> {$item['end']}\r\n" . (!empty($item['en']) ? $item['en'] . "\r\n" : '') . (!empty($item['cn']) ? $item['cn'] . "\r\n" : '');
        }
        $file = public_path('word') . $video['title'] . '.srt';
        if (!is_dir(dirname($file))) {
            mkdir(dirname($file), 0755, true);
        }
        file_put_contents($file, implode("\r\n\r\n", $data));
        return "http://api.doctorsclass.com/word/{$video['title']}.srt";
    }

    // 删除字幕
    public function deleteWordScreenItem($id, $adminId)
    {
        $word = Db::table("video_wordscreen")->where(['id' => $id])->find();
        if (!$word) {
            throw new BackErrorException('字幕数据不存在');
        }
        $video = Db::table("video_list")->where(['id' => $word['video_id']])->find();
        if (!$video || (0 !== $adminId && $video['wordscreen_editor'] != $adminId)) {
            throw new BackErrorException("没有权限操作");
        }
        Db::table("video_wordscreen")->where(['id' => $id])->delete();
    }

    public function supplyWordScreen($videoId, $adminId)
    {
        $video = Db::table("video_list")->where(['id' => $videoId])->find();
        if ($video['wordscreen_editor'] != $adminId) {
            throw new BackErrorException("没有权限操作");
        }
        Db::table("video_list")->where(['id' => $videoId])->update(['status' => 2]);
    }

    public function sureWordScreen($videoId, $admin)
    {
        if (!in_array("admin", $admin['roles'])) {
            throw new BackErrorException("没有操作权限");
        }
        $video = Db::table("video_list")->where(['id' => $videoId])->find();
        if ($video['status'] != 2) {
            throw new BackErrorException("不能对该字幕进行审核");
        }
        Db::table("video_list")->where(['id' => $videoId])->update(['status' => 3]);
    }

    public function sendBackWordScreen($videoId, $admin)
    {
        if (!in_array("admin", $admin['roles'])) {
            throw new BackErrorException("没有操作权限");
        }
        $video = Db::table("video_list")->where(['id' => $videoId])->find();
        if ($video['status'] != 2 && $video['status'] != 3) {
            throw new BackErrorException("不能对该字幕进行此项操作");
        }
        //发回公海
        Db::table("video_list")->where(['id' => $videoId])->update(['status' => 0, 'wordscreen_editor' => 0]);
    }

    /**
     * 更新视频进度
     * @param $videoId
     * @param $userId
     * @param $timeSecond
     * @param $watchTime
     * @return bool|null
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public static function updateProgress($videoId, $userId, $watchTime)
    {
        $video = VideoListModel::where(['id' => $videoId])->find();
        if (!$video) {
            return false;
        }
        $study = UserStudy::where(['video_id' => $videoId, 'uid' => $userId])->find();
        if (!$study) {
            // 新一个用户开始观看视频时，为其热度+1
            $video->hot++;
            $video->save();
            $progressAdd = false;
            // 新增视频进度
            $study = new UserStudy();
            $study->video_id = $videoId;
            $study->uid = $userId;
        } else {
            if ($video->duration == 0.00 || is_null($video->duration)) {
                throw new Exception('视频时长有误，请检查~');
            }
            // 计算进度百分比
            $progressAdd = true;
            $study->progress = self::getProgressNew($watchTime, $study->play_time, $video->duration);
            $study->play_time = self::getSumPlayTime($study->play_time, $watchTime, $study->progress, $video->duration);
            $study->today_time = self::getTodayTime($study->update_time, $video->duration, $study->today_time, $watchTime);
        }
        $study->save();
        // 在视频属于某个专栏时，并增加了进度时，更新学习进度
        if ($video->topic_id > 0 && $progressAdd) {
            // 增加到总学时
            UserService::setExtValueIncr($userId, UserService::TYPE_EXT_TOTAL_STUDY_TIME, $watchTime);
            // 更新专栏进度
            StudyPlanService::updateProgress($video->topic_id, 2, $userId);
        }
        return true;
    }

    /**
     * 获取进度
     * @param $watchTime
     * @param $playTime
     * @param $allTime
     * @return float|string
     */
    public static function getProgressNew($watchTime, $playTime, $allTime)
    {
        $progress = sprintf('%.2f', (($watchTime + $playTime) / $allTime) * 100);
        if ($progress >= 100.00) {
            $progress = 100.00;
        }
        return $progress;
    }

    /**
     * 获取观看时常
     * @param $playTime
     * @param $watchTime
     * @param $progress
     * @param $videoTime
     * @return mixed
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public static function getSumPlayTime($playTime, $watchTime, $progress, $videoTime)
    {
        if ($progress == 100) {
            return $videoTime;
        } else {
            return $playTime + $watchTime;
        }
    }

    /**
     * 获取今日时间
     * @param $originTime
     * @param $duration
     * @param $todayTime
     * @param $watchTime
     * @return int|mixed
     */
    public static function getTodayTime($originTime, $duration, $todayTime, $watchTime)
    {
        if (strtotime($originTime) < strtotime('today')) {
            $today = 0;
        } else {
            $today = max(0, min($duration, $todayTime + $watchTime));
        }
        return $today;
    }

    /**
     * 获取指定视频的播放进度
     * @param $videoId
     * @param $userId
     * @return int
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public static function getPlayTime($videoId, $userId)
    {
        if ($study = UserStudy::where(['video_id' => $videoId, 'uid' => $userId])->find()) {
            return (int)$study->play_time;
        } else {
            return 0;
        }
    }

    /**
     * @param $videoId
     * @param $userId
     * @return float|int
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public static function getProgress($videoId, $userId)
    {
        if ($study = UserStudy::where(['video_id' => $videoId, 'uid' => $userId])->find()) {
            return (float)$study->progress;
        } else {
            return 0;
        }
    }

    /**
     * 统计所有今日学习的时长，返回秒数
     * @param $userId
     * @return float
     */
    public static function getTodayStudyTime($userId)
    {
        return UserStudy::where(['uid' => $userId])->where('update_time', '>=', date('Y-m-d 00:00:00'))->sum('today_time');
    }
}